package com.zx;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zx.annotation.DataClass;
import com.zx.annotation.DataField;
import com.zx.enums.DataTypeEnum;
import com.zx.exception.DataParseException;
import com.zx.model.DataClassModel;
import com.zx.model.DataFieldModel;
import com.zx.process.AbstractDataConfigProcess;
import com.zx.process.impl.TextDataConfigProcess;
import com.zx.util.ConverterFactory;
import com.zx.util.DataClassProcessHandlerFactory;
import com.zx.util.DataFieldProcessHandlerFactory;
/**
 * @Project: dataParse-core
 * @Title: ParseFactory
 * @Description: 解析器工程
 * @author: xue.zhang
 * @date: 2018年2月12日下午4:28:53
 * @company: alibaba
 * @Copyright: Copyright (c) 2017
 * @version v1.0
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class ParseFactory {
	
	private static Logger logger = LoggerFactory.getLogger(ParseFactory.class);
	
	/** 保存实例化之后的解析器 */
	private static Map<String, AbstractDataConfigProcess> dataMapper = new ConcurrentHashMap<String, AbstractDataConfigProcess>();
	
	/* ***********************  1. 注册类的解析器    *********************************************/
	public static AbstractDataConfigProcess register(String classFullName) throws Exception {
		try {
			Class<?> clazz = Class.forName(classFullName);
			return register(clazz);
		} catch (Exception e) {
			throw e;
		}
	}
	
	public static <T> AbstractDataConfigProcess<T> register(Class<T> clazz) throws DataParseException {
		try {
			// 检验配置
			if(!checkRegisterClass(clazz)) {
				throw new DataParseException("注册异常,  class " + DataClass.class.getName() + " 校验配置异常");
			}
			// 获得文件配置
			DataClassModel<T> dataClassModel = getDataClassModel(clazz);
			if(dataClassModel == null) {
				throw new DataParseException("注册异常,  class " + DataClass.class.getName() + " 不能获得文件配置注解");
			}
			// 获得字段配置
			Field[] declaredFields = clazz.getDeclaredFields();//获得字段的注解信息
			for (Field field : declaredFields) {
				DataFieldModel fieldModel = getDataFieldModel(field);
				if(fieldModel != null) {
					if(dataClassModel.getFieldMap().containsKey(fieldModel.getIndex())) {
						throw new DataParseException("注册异常,  class " + DataClass.class.getName() + " 多个字段公用一个index");
					} else {
						dataClassModel.getFieldMap().put(fieldModel.getIndex(), fieldModel);
					}
				}
			}
			// 校验字段配置是否存在
			if(dataClassModel.getFieldMap().size() == 0) {
				throw new DataParseException("注册异常,  class " + DataClass.class.getName() + " 不能获得字段配置注解");
			}
			// 获得文本解析器
			AbstractDataConfigProcess<T> dataProcess = getDataProcess(dataClassModel);
			if(dataProcess == null) {
				throw new DataParseException("注册异常,  class " + DataClass.class.getName() + " 获得文本解析器异常");
			}
			
			dataMapper.put(clazz.getName(), dataProcess);
			
			return dataMapper.get(clazz.getName());
		} catch (Exception e) {
			throw new DataParseException(e, "模板类【" + clazz + "】注册失败");
		}
	}
	
	/* ***********************  2. 注销类的解析器    *********************************************/
	public static void unRegister(String classFullName) {
		dataMapper.remove(classFullName);
	}
	
	public static <T> void unRegister(Class<T> clazz) {
		unRegister(clazz.getName());
	}
	
	/* ***********************  3. 获得类的解析器    *********************************************/
	public static AbstractDataConfigProcess<?> getMapper(String classFullName) {
		return dataMapper.get(classFullName);
	}
	
	public static <T> AbstractDataConfigProcess<T> getMapper(Class<T> clazz) {
		return dataMapper.get(clazz.getName());
	}
	
	/* ***********************  4. 内部工具方法    *********************************************/
	/**
	 * @title 获得类的配置
	 * @param clazz
	 * @return
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2019年1月10日下午8:43:04
	 */
	private static <T> DataClassModel<T> getDataClassModel(Class<T> clazz) throws DataParseException{
		DataClass dataConfig = clazz.getAnnotation(DataClass.class);
		if(dataConfig == null) {
			return null;
		}
		
		// 类的配置
		DataClassModel<T> classModel = new DataClassModel<T>();
		classModel.setRegisterClass(clazz);
		classModel.setCharset(dataConfig.charset());
		classModel.setDataType(dataConfig.dataType());
		classModel.setSplit(dataConfig.split());
		classModel.setLineDataLength(dataConfig.lineDataLength());
		classModel.setArrayInterval(dataConfig.arrayInterval());
		classModel.setArrayLength(dataConfig.arrayLength());
		// 类(针对一行数据)--处理器--工厂
		classModel.setCheckedHandler(DataClassProcessHandlerFactory.getProcessHandler(clazz));
		
		return classModel;
	}
	
	
	/**
	 * @title 获得字段的配置
	 * @param clazz
	 * @return
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2019年1月10日下午8:44:56
	 */
	private static DataFieldModel getDataFieldModel(Field field) throws DataParseException{
		DataField columnConfig = field.getAnnotation(DataField.class);
		if(columnConfig == null) {
			return null;
		}
		
		// 字段的配置
		DataFieldModel dataFieldModel = new DataFieldModel();
		dataFieldModel.setDesc(columnConfig.desc());
		dataFieldModel.setField(field);
		dataFieldModel.setIndex(columnConfig.index());
		dataFieldModel.setDatePattern(columnConfig.datePattern());
		dataFieldModel.setIsNull(columnConfig.isNull());
		dataFieldModel.setDefaultValue(columnConfig.defaultValue());
		dataFieldModel.setMaxLength(columnConfig.maxLength());
		
		// 获得类型转换器
		dataFieldModel.setConverter(ConverterFactory.getConverter(field));
		// 字段--处理器--工厂
		dataFieldModel.setCheckedHandler(DataFieldProcessHandlerFactory.getProcessHandler(field));
		
		return dataFieldModel;
	}
	
	/**
	 * @title 校验类是否能够进行注册
	 * @param clazz
	 * @return
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @date 2019年1月10日下午8:45:17
	 */
	private static <T> boolean checkRegisterClass(Class<T> clazz) throws DataParseException{
		// 校验配置是否存在
		DataClass dataConfig = clazz.getAnnotation(DataClass.class);
		if(dataConfig == null) {
			return false;
		}
		
		// 校验文件格式类型
		boolean flag = false;
		DataTypeEnum dataType = dataConfig.dataType();
		logger.info("开始获取注解的配置 {}, 文件类型 {}", clazz.getName(), dataType);
		
		if(dataType.equals(DataTypeEnum.TEXT)) {
			flag = true;
		} else if(dataType.equals(DataTypeEnum.EXCEL)) {
			logger.info("开始获取注解的配置 {}, 暂不支持 Excel 格式的文件解析", clazz.getName());
			flag = false;
		} else if(dataType.equals(DataTypeEnum.BIN)) {
			logger.info("开始获取注解的配置 {}, 暂不支持 二进制 格式的文件解析", clazz.getName());
			flag = false;
		} else {
			logger.info("开始获取注解的配置 {}, 文件格式异常", clazz.getName());
			flag = false;
		}
		
		return flag;
	}
	
	/**
	 * @title 获得文本解析器
	 * @param clazz
	 * @return
	 * @throws DataParseException
	 * @author: xue.zhang
	 * @param <T>
	 * @date 2019年1月10日下午8:44:56
	 */
	private static <T> AbstractDataConfigProcess<T> getDataProcess(DataClassModel<T> dataClassModel) throws DataParseException{
		AbstractDataConfigProcess process = null;
		DataTypeEnum dataType = dataClassModel.getDataType();
		if(dataType.equals(DataTypeEnum.TEXT)) {
			process = new TextDataConfigProcess<T>(dataClassModel);
		} else if(dataType.equals(DataTypeEnum.EXCEL)) {
			logger.info("暂不支持 Excel 格式的文件解析");
		} else if(dataType.equals(DataTypeEnum.BIN)) {
			logger.info("暂不支持 二进制 格式的文件解析");
		} else {
			logger.info("文件格式异常");
		}
		return process;
	}
}
